package main

import (
	"context"
	"fmt"
	"log"
	"time"

	//"bytes"
	"io/ioutil"

	"github.com/chromedp/chromedp"

	//"io"
	//"bufio"
	//"net/http"
	"image"
	"image/png"
	"os"
	"os/exec"
	"strings"

	//"github.com/makiuchi-d/gozxing"
	//"github.com/makiuchi-d/gozxing/qrcode"
	"github.com/chromedp/cdproto/network"
	//goQrcode "github.com/skip2/go-qrcode"
	//"github.com/gocolly/colly"
)

var loginResult string

func main() {
	fmt.Println("good luckly....")
	go_check()
	if loginResult == "ok" {
		fmt.Println("已经登录过无须再次登录....")
		go_kill()

	} else {
		fmt.Println("登录开始....")
		go_login()
		go_kill()
	}
}

func go_check() {
	options := []chromedp.ExecAllocatorOption{
		chromedp.Flag("headless", true), // debug使用 //*[@id="btn-reservation"]
		chromedp.Flag("blink-settings", "imagesEnabled=false"),
		chromedp.UserAgent(`Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36`),
		chromedp.WindowSize(1024, 1024),
	}

	options = append(chromedp.DefaultExecAllocatorOptions[:], options...)

	c, _ := chromedp.NewExecAllocator(context.Background(), options...)

	chromeCtx, cancel := chromedp.NewContext(c, chromedp.WithLogf(log.Printf))
	defer cancel()

	timeoutCtx, cancel := context.WithTimeout(chromeCtx, 180*time.Second)
	defer cancel()

	err := chromedp.Run(timeoutCtx,
		loadCookies(),
		chromedp.Navigate(`https://home.jd.com/`),
		checkLoginStatus(),
	)

	if err != nil {
		//fmt.Println("hello world12221")
		log.Fatal(err)
	}
}

func go_login() {

	options := []chromedp.ExecAllocatorOption{
		chromedp.Flag("headless", false), // debug使用
		//   chromedp.Flag("blink-settings", "imagesEnabled=false"),
		chromedp.UserAgent(`Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36`),
		chromedp.WindowSize(1024, 1024),
	}

	options = append(chromedp.DefaultExecAllocatorOptions[:], options...)

	c, _ := chromedp.NewExecAllocator(context.Background(), options...)

	chromeCtx, cancel := chromedp.NewContext(c, chromedp.WithLogf(log.Printf))
	defer cancel()

	timeoutCtx, cancel := context.WithTimeout(chromeCtx, 180*time.Second)
	defer cancel()

	var res string

	err := chromedp.Run(timeoutCtx,
		chromedp.Navigate(`https://www.jd.com/`),
		chromedp.WaitVisible(`#J_footer`, chromedp.ByID),
		chromedp.Click(`//*[@id="ttbar-login"]/a[1]`),
		chromedp.WaitVisible(`//*[@id="content"]/div[2]/div[1]/div/div[5]/div/div[2]/div[1]/img`, chromedp.BySearch),
		chromedp.Evaluate(`var qc=document.getElementsByClassName('qrcode-img')[0];qc.className='';var qc2=document.getElementsByClassName('qrcode-help')[0];qc2.className='';`, &res),
		chromedp.WaitVisible(`//*[@id="content"]/div[2]/div[1]/div/div[5]/div/div[2]/div[1]/img`, chromedp.BySearch),
		getCode(),
		saveCookies(),
	)

	if err != nil {
		log.Fatal(err)
	}
}
func go_kill() {

	options := []chromedp.ExecAllocatorOption{
		chromedp.Flag("headless", false), // debug使用
		chromedp.Flag("blink-settings", "imagesEnabled=false"),
		chromedp.UserAgent(`Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36`),
	}
	c, _ := chromedp.NewExecAllocator(context.Background(), options...)

	chromeCtx, cancel := chromedp.NewContext(c, chromedp.WithLogf(log.Printf))
	defer cancel()

	timeoutCtx, cancel := context.WithTimeout(chromeCtx, 360*time.Second)
	defer cancel()

	err2 := chromedp.Run(timeoutCtx,
		loadCookies(),
		KillMaoTai(),
	)

	if err2 != nil {
		log.Fatal(err2)
	}
}

func KillMaoTai() chromedp.ActionFunc {
	return func(ctx context.Context) (err error) {
		fmt.Println("预约抢购。。。。")
		var res string
		if err = chromedp.Navigate(`https://item.jd.com/100012043978.html`).Do(ctx); err != nil {
			return
		}
		//reservation //*[@id="btn-reservation"]
		if err = chromedp.Click(`#btn-reservation`).Do(ctx); err != nil {
			return
		}
		if err = chromedp.WaitVisible(`//*[@id="container"]/div/div[1]/div/div[2]/p[4]/a[1]`).Do(ctx); err != nil {
			return
		}
		if err = chromedp.Navigate(`https://item.jd.com/100012043978.html`).Do(ctx); err != nil {
			return
		}

		//*[@id="btn-reservation"] //*[@id="btn-reservation"]
		if err = chromedp.Text(`#btn-reservation`, &res, chromedp.NodeVisible, chromedp.ByID).Do(ctx); err != nil {
			return
		}
		fmt.Println("当前状态：" + res)
		if res != "开始预约" {
			if err = chromedp.Click(`#btn-reservation`).Do(ctx); err != nil {
				return
			}

		} else {
			fmt.Println("刷新页面。。。。")
			for {
				if res == "抢购" {
					if err = chromedp.Click(`#btn-reservation`).Do(ctx); err != nil {
						return
					}
					var url string

					if err = chromedp.Evaluate(`window.location.href`, &url).Do(ctx); err != nil {
						return
					}
					if strings.Contains(url, "marathon.jd.com") {
						fmt.Println("进入提交页面。。。。")
						//chromedp.Stop()
						//提交订单submit //*[@id="app"]/div/div[2]/div/div[5]/div[3]/div[2]/div/div/div/button
						////*[@id="app"]/div/div[2]/div/div[5]/div[3]/div[2]/div/div/div/button/text()
						// if err = chromedp.Submit(`//*[@id="app"]/div/div[2]/div/div[5]/div[3]/div[2]/div/div/div/button`, chromedp.BySearch).Do(ctx); err != nil {
						// 	return
						// }
						if err = chromedp.Evaluate(`document.forms[0].submit();`, &res).Do(ctx); err != nil {
							return
						}
						for {
							if err = chromedp.Evaluate(`window.location.href`, &url).Do(ctx); err != nil {
								return
							}
							if strings.Contains(url, "marathon.jd.com") {
								if err = chromedp.Evaluate(`document.forms[0].submit();`, &res).Do(ctx); err != nil {
									return
								}
							} else {
								break
							}

						}
					}
				}
				if err = chromedp.Navigate(`https://item.jd.com/100012043978.html`).Do(ctx); err != nil {
					return
				}
				if err = chromedp.Text(`#btn-reservation`, &res, chromedp.NodeVisible, chromedp.ByID).Do(ctx); err != nil {
					return
				}
				fmt.Println("当前状态：" + res)
			}
		}
		if err = chromedp.WaitVisible(`//*[@id="container23"]/div/div[1]/div/div[2]/p[4]/a[1]`).Do(ctx); err != nil {
			return
		}

		fmt.Println("结束抢购，祝你好运")
		//	chromedp.WaitVisible(`#shSafetyPV`, chromedp.ByID), //*[@id="app"]/div/div[2]/div/div[5]/div[3]/div[2]/div/div/div/button/text()
		//chromedp.Navigate(`https://item.jd.com/100012043978.html`),
		return
	}
}

func LoadImage(path string) (img image.Image, err error) {
	file, err := os.Open(path)
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()
	img, err = png.Decode(file)
	return
}

func getCode() chromedp.ActionFunc {
	return func(ctx context.Context) (err error) {
		// 1. 用于存储图片的字节切片 //*[@id="cart-body"]/div[1]/div[5]/div/div[2]/div/div/div/div[2]/div[2]/div/div[1]/a 去结算
		var code []byte

		// 2. 截图 //*[@id="tryBtn"] 再次抢购
		// 注意这里需要注明直接使用ID选择器来获取元素（chromedp.ByID）
		//document.querySelector("#content > div.login-wrap > div.w > div > div.qrcode-login > div > div.qrcode-main > div.qrcode-img > img")
		//*[@id="content"]/div[2]/div[1]/div/div[5]/div/div[2]/div[1]/img
		///html/body/div[2]/div[2]/div[1]/div/div[5]/div/div[2]/div[1]/img
		if err = chromedp.Screenshot(`//*[@id="content"]/div[2]/div[1]/div/div[5]/div/div[2]/div[1]/img`, &code, chromedp.BySearch).Do(ctx); err != nil {
			return
		}

		// 3. 保存文件
		if err = ioutil.WriteFile("code2.png", code, 0755); err != nil {
			return
		}

		if err = printQRCode(code); err != nil {
			fmt.Println("png err")
			return err
		}
		return
	}
}

func printQRCode(code []byte) (err error) {
	c := exec.Command("cmd", "/C", "start", "code2.png")
	if err := c.Run(); err != nil {
		fmt.Println("Error: ", err)
	}
	// 1. 因为我们的字节流是图像，所以我们需要先解码字节流
	// img, _, err := image.Decode(bytes.NewReader(code))
	// if err != nil {
	// 	fmt.Println("png err 0000")
	// 	return
	// }

	// // 2. 然后使用gozxing库解码图片获取二进制位图
	// bmp, err := gozxing.NewBinaryBitmapFromImage(img)
	// if err != nil {
	// 	fmt.Println("png err 1111")
	// 	return
	// }

	// // 3. 用二进制位图解码获取gozxing的二维码对象
	// res, err := qrcode.NewQRCodeReader().Decode(bmp, nil)
	// if err != nil {
	// 	fmt.Println("png err 2222")
	// 	return
	// }

	// // 4. 用结果来获取go-qrcode对象（注意这里我用了库的别名）
	// qr, err := goQrcode.New(res.String(), goQrcode.High)
	// if err != nil {
	// 	fmt.Println("png err 3333333333")
	// 	return
	// }

	// // 5. 输出到标准输出流
	// fmt.Println(qr.ToSmallString(false))
	return
}

// 保存Cookies
func saveCookies() chromedp.ActionFunc {
	return func(ctx context.Context) (err error) {
		// 等待二维码登陆
		if err = chromedp.WaitVisible(`#ttbar-myjd`, chromedp.ByID).Do(ctx); err != nil {
			return
		}

		// cookies的获取对应是在devTools的network面板中
		// 1. 获取cookies
		cookies, err := network.GetAllCookies().Do(ctx)
		if err != nil {
			return
		}

		// 2. 序列化
		cookiesData, err := network.GetAllCookiesReturns{Cookies: cookies}.MarshalJSON()
		if err != nil {
			return
		}

		// 3. 存储到临时文件
		if err = ioutil.WriteFile("cookies.tmp", cookiesData, 0755); err != nil {
			return
		}
		return
	}
}

// 检查是否登陆
func checkLoginStatus() chromedp.ActionFunc {
	////*[@id="ttbar-login"]/div[1]/a  登录名称 #ttbar-myjd  https://home.jd.com/  _MYJD_order
	//	var res string

	return func(ctx context.Context) (err error) {
		var url string

		if err = chromedp.Evaluate(`window.location.href`, &url).Do(ctx); err != nil {
			return
		}
		if strings.Contains(url, "https://home.jd.com") {
			log.Println("已经使用cookies登陆")
			loginResult = "ok"
			fmt.Println("登录成功。。。。。")
			//chromedp.Stop()
		}
		return
	}
}

// 加载Cookies
func loadCookies() chromedp.ActionFunc {
	return func(ctx context.Context) (err error) {
		// 如果cookies临时文件不存在则直接跳过
		if _, _err := os.Stat("cookies.tmp"); os.IsNotExist(_err) {
			return
		}

		// 如果存在则读取cookies的数据
		cookiesData, err := ioutil.ReadFile("cookies.tmp")
		if err != nil {
			return
		}

		// 反序列化
		cookiesParams := network.SetCookiesParams{}
		if err = cookiesParams.UnmarshalJSON(cookiesData); err != nil {
			return
		}

		// 设置cookies
		return network.SetCookies(cookiesParams.Cookies).Do(ctx)
	}
}
